package Dungeon;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import SquarePackage.Direction;
import SquarePackage.Square;

/**
 * Class for a composed dungeon. This is a dungeon with subdungeons in it.
 * 
 * @invar	All coordinates are positive and smaller than the maximum value.
 * 			| isValidDimension()
 * 
 * @author 	Brecht Reynders en Florian Hendrickx
 * @version 1.0
 */
public class ComposedDungeon extends Subdungeon {
	
	/**
	 * Initializes a new dungeon with the given coordinates.
	 * 
	 * @param	maxX
	 * 			The maximum x-coordinate value.
	 * @param	maxY
	 * 			The maximum y-coordinate value.
	 * @param	maxZ
	 * 			The maximum z-coordinate value.
	 * @effect	The given coordinates are the coordinates of the maximum dimension.
	 * 			| super(maxX, maxY, maxZ) 
	 */
	public ComposedDungeon(long maxX, long maxY, long maxZ){
		super(maxX, maxY, maxZ);
		this.dungeons = new HashMap<Dimension, Subdungeon>();
	}
		
	/**
	 * Initializes a new dungeon with the given dimension as maximum dimension.
	 * 
	 * @param 	maxDimension
	 * 			The maximum dimension
	 * @effect	The given maximum dimension is the new max dimension.
	 * 			| super(maxDimension)
	 */
	public ComposedDungeon(Dimension maxDimension){
		super(maxDimension);
		this.dungeons = new HashMap<Dimension, Subdungeon>();
	}

	/**
	 * Variable registering the dungeons in this composed dungeon and their starting position.
	 */
	private Map<Dimension, Subdungeon> dungeons;
	
	/**
	 * Returns the dungeons and their starting dimensions.
	 */
	public Map<Dimension,Subdungeon> getDungeons(){
		return dungeons;
	}
	
	/**
	 * Returns all the starting dimensions of the dimensions of this composed dungeon.
	 */
	public Set<Dimension> getDimensions(){
		return dungeons.keySet();
	}
	
	public Collection<Subdungeon> getAllDungeons(){
		return getDungeons().values();
	}
	
	/**
	 * Adds a subdungeon to this dungeon.
	 * 
	 * @param 	subdungeon
	 * 			The dungeon to be added to this dungeon.
	 * @post	
	 */
	public void addDungeon(Subdungeon subdungeon){
		fit(null, null);
		//TODO 
	}
	
	/**
	 * Removes a subdungeon from this dungeon.
	 * 
	 * @param 	subdungeon
	 * 			The dungeon to remove from this dungeon.
	 * @post	
	 */
	public void removeDungeon(Subdungeon subdungeon){
		//TODO}
	}
	
	/**
	 * Checks whether this dungeon could fit in this dungeon at the given dimension.
	 * 
	 * @param 	dimension
	 * 			The dimension where the dungeon gets added.
	 * @param 	subdungeon
	 * 			The dungeon which is going to be added.
	 * @return	True if and only if there is enough space for the given dungeon to be added in this dungeon.
	 * 			| for each dimension in dungeons
	 * 			| if(dungeon.getMaxDimension()
	 */
	private boolean fit(Dimension dimension, Subdungeon subdungeon){
		//TODO 
		return false;
	}
	
	protected Dimension getDimensionOf(Square square){
		for(Subdungeon dungeon : getAllDungeons()){
			Dimension dimension = dungeon.getDimensionOf(square);
			if(dimension != null)
				return dimension;
		}
		return null;
	}
	
	public Square getSquareAt(Dimension absoluteDimension){
		Subdungeon sub = getDungeonAt(absoluteDimension);
		if(sub != null)
			return sub.getSquareAt(absoluteDimension.subtract(getDimensionOfDungeon(sub)));
		return null;
	}
	
	private Subdungeon getDungeonAt(Dimension dimension){
		for(Dimension startDimension : getDimensions()){
			if(startDimension.isSmallerThan(dimension)){
				Dimension newDimension = dimension.subtract(startDimension);
				if(newDimension.isSmallerThan(getDungeons().get(startDimension).getMaxDimension()))
					return getDungeons().get(startDimension);
			}	
		}
		return null;
	}
	
	private Dimension getDimensionOfDungeon(Subdungeon subdungeon){
		for(Dimension dimension : getDimensions()){
			if(getDungeons().get(dimension).equals(subdungeon))
				return dimension;
		}
		return null;
	}
	
	public void openDoor(Square square, Direction direction){//TODO
		
	}
	
	public void closeDoor(Square square, Direction direction){
		//TODO
	}
	
	public void removeSquareAt(Dimension dimension){
		if(getDungeonAt(dimension)!=null)
			getDungeonAt(dimension).removeSquareAt(dimension.subtract(getDimensionOfDungeon(getDungeonAt(dimension))));
	}
	
	public boolean hasBeenUsed(Square square){
		for(Subdungeon dungeon: getAllDungeons()){
			if(dungeon.hasBeenUsed(square))
				return true;
		}
		return false;
	}
	
	private Dimension getDimensionIn(Subdungeon dungeon, Dimension dimension){
		return dimension.subtract(dungeon.getMaxDimension());
	}
	
	public void addSquare(Square square, Dimension dimension){
		getDungeonAt(dimension).addSquare(square, getDimensionIn(getDungeonAt(dimension), dimension));
	}
}
